from abc import ABC, abstractmethod
from typing import Any, List

from .validator import Required, Validate


class VerifyResult:
    ok: bool
    msg_suffix: str

    def __init__(self, ok = True, msg = '') -> None:
        self.ok = ok
        self.msg_suffix = msg

    def __str__(self) -> str:
        return f'<{self.__class__}> {self.ok}  {self.msg_suffix}'

    def __repr__(self) -> str:
        return self.__str__()


class Field(ABC):
    default: Any = None
    required: bool = False
    json_key: str = None
    protected: bool = False

    def __init__(self,
                 required: bool = False,
                 json_key: str = '',
                 default: Any = None,
                 protected: bool = False,
                 validators: List[Validate] = None,
                 desc: str = '') -> None:
        '''
        :param bool required: 是否必填字段
        :param str json_key: 生成字典的键名
        :param bool protected: 字段是否受到保护, 受到保护字段不能直接通过'.'的方式修改
        :param Any default: 字段默认值
        :param str desc: 字段描述信息
        :param list validators: 校验器
        '''
        if validators is None:
            validators = []
        self.json_key = json_key
        self.required = required
        self.default = default
        self.protected = protected
        self.desc = desc
        self.validators = validators
        if default:
            self.value = default
        else:
            self.value = None
        if required:
            self.validators.append(Required())

    def __repr__(self) -> str:
        return f'<{self.__class__}> required({self.required}) default({self.default}) json_key({self.json_key})'

    def __str__(self) -> str:
        return self.__repr__()

    def validate(self) -> VerifyResult:
        res = VerifyResult()
        value = self.output()
        for v in self.validators:
            if not v.validate(value):
                res.ok = False
                res.msg_suffix = v.msg_suffix
                break
        return res

    @abstractmethod
    def output(self):
        pass
